using System;
using System.Diagnostics;
using System.Timers;
using System.Xml;

namespace FozDesk.Extensions
{
    public partial class SendKeysEx
    {
        private XmlDocument _XmlInput;
        private int _Retries;

        public SendKeysEx()
        {
        }

        #region SendXml
        public void SendXml(XmlDocument XmlInput, String CommandId)
        {
            if (_XmlInput == null) _XmlInput = new XmlDocument();
            _XmlInput = XmlInput;
            SendXml(CommandId);
        }

        public void SendXml(string XmlFilePath, String CommandId)
        {
            if (_XmlInput == null) _XmlInput = new XmlDocument();
            _XmlInput.Load(XmlFilePath);
            SendXml(CommandId);
        }

        private void SendXml(String CommandId)
        {
            XmlNodeList CommandItems = _XmlInput.GetElementsByTagName("command");
            if (CommandItems.Count != 0)
            {
                foreach (XmlNode CommandItem in CommandItems)
                {
                    if(CommandItem.Attributes[ID].Value.Equals(CommandId))
                    {
                        CommandItems = CommandItem.ChildNodes;
                        break;
                    }
                }
            }
            if (CommandItems.Count != 0)
            {
                foreach (XmlNode CommandItem in CommandItems)
                {
                    ExecuteCommand(CommandItem);
                }
            }
        }

        private void ExecuteCommand(XmlNode CommandItem)
        {
            switch (CommandItem.Name.ToLower())
            {
                case SEND:
                    Send(CommandItem.Attributes[VALUE].Value);
                    break;
                case SENDWAIT:
                    SendWait(CommandItem.Attributes[VALUE].Value);
                    break;
                case LAUNCH:
                    Process.Start(CommandItem.Attributes[PROCESS].Value);
                    break;
                case FOCUS:
                    FocusWindow(CommandItem.Attributes[PROCESS].Value,
                        CommandItem.Attributes[TITLE].Value);
                    break;
                case MOVE:
                    SendMove(uint.Parse(CommandItem.Attributes[X].Value),
                        uint.Parse(CommandItem.Attributes[Y].Value));
                    break;
                case WAIT:
                    Sleep(Int32.Parse(CommandItem.Attributes[DELAY].Value));
                    break;
                case CLICK:
                    SendClick(uint.Parse(CommandItem.Attributes[X].Value),
                        uint.Parse(CommandItem.Attributes[Y].Value));
                    break;
                case DBLCLICK:
                    SendDoubleClick(uint.Parse(CommandItem.Attributes[X].Value),
                        uint.Parse(CommandItem.Attributes[Y].Value));
                    break;
            }
        }
        #endregion

        #region Window Methods
        private void FocusWindow(String WindowClass, String WindowCaption)
        {
            _WindowClass = WindowClass;
            _WindowCaption = WindowCaption;
            WaitForWindow();
            SetForegroundWindow(_WindowHandle);
        }

        private void WaitForWindow()
        {
            //sleep and check for IsWindow or a bool
            while (!IsWindow())
            {
                Sleep();
                _Retries++;
                if (_Retries > MAXRETRY)
                {
                    _Retries = 0;
                    throw new TimeoutException(TIMEOUT);
                }
            }
        }

        private Boolean IsWindow()
        {
            if (_WindowClass.Equals(String.Empty)
                || _WindowCaption.Equals(String.Empty))
                return false;
            _WindowHandle = FindWindow(_WindowClass, _WindowCaption);
            return (_WindowHandle != IntPtr.Zero);
        }
        #endregion

        #region Mouse Events
        public void SendMove(UInt32 X, UInt32 Y)
        {
            mouse_event(MOUSEEVENTMOVE, X, Y, 0, new System.IntPtr());
        }

        public void SendClick(UInt32 X, UInt32 Y)
        {
            mouse_event(MOUSEEVENTLEFTDOWN, X, Y, 0, new System.IntPtr());
            mouse_event(MOUSEEVENTLEFTUP, X, Y, 0, new System.IntPtr());
        }

        public void SendDoubleClick(UInt32 X, UInt32 Y)
        {
            SendClick(X, Y);
            SendClick(X, Y);
        }
        #endregion
    }
}
